﻿using System.Web;
using System.Web.Mvc;
using ActivateYourGlutes.Helpers;
using ActivateYourGlutes.Infrastructure;
using ActivateYourGlutes.Infrastructure.Logging;
using ActivateYourGlutes.Services;
using ActivateYourGlutes.Services.Model;
using Microsoft.Practices.ServiceLocation;

namespace ActivateYourGlutes.Controllers
{
    /// <summary>
    /// A controller deriving from this class gains access to the locale settings for the current
    /// user in its actions.
    /// </summary>
    public abstract partial class LocalisingController : Controller
    {
        public const string LocaleSessionKey = "_localisation";
        public const string LocaleViewDataKey = "localeSettings";
        public const string IsAdministratorViewDataKey = "IsAdministrator";

        protected IAccountProvider AccountProvider { get; private set; }

        internal ILogger Logger { get; private set; }

        protected LocalisingController(IAccountProvider accountProvider, ILogger logger)
        {
            AccountProvider = accountProvider;
            Logger = logger;
        }

        private Account _currentAccount;
        /// <summary>
        /// The logged in user, if any
        /// </summary>        
        protected Account CurrentAccount
        {
            get
            {
                if (_currentAccount == null && User.Identity.IsAuthenticated)
                    _currentAccount = AccountProvider.CurrentAccount(User);                
                return _currentAccount;
            }
        }

        private UserLocaleSettings _localeSettings;
        public UserLocaleSettings LocaleSettings { get { return _localeSettings; } internal set { _localeSettings = value;} }

        /// <summary>
        /// Set the locale settings in view data just before the action executes
        /// </summary>
        /// <param name="filterContext"></param>
        protected override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            base.OnActionExecuting(filterContext);
            // Place the localesettings into view data
            if (_localeSettings == null)
                throw new LocalisationException("Locale has not been set");
            ViewData[LocaleViewDataKey] = _localeSettings;
            ViewData[IsAdministratorViewDataKey] = CurrentAccount == null ? false : CurrentAccount.IsAdministrator;
        }

        /// <summary>
        /// Establish our locale settings when the controller is initialsied
        /// </summary>
        protected override void Initialize(System.Web.Routing.RequestContext requestContext)
        {
            base.Initialize(requestContext);
            InitialiseLocaleSettings(requestContext.HttpContext);
        }

        /// <summary>
        /// Initialise the locale settings
        /// </summary>
        /// <param name="httpContext"></param>
        protected virtual void InitialiseLocaleSettings(HttpContextBase httpContext)
        {
            var locale = (UserLocaleSettings)httpContext.Session[LocaleSessionKey];
            if (locale == null)
            {
                locale = LocaleFactory.GetLocale(httpContext);
                ControllerContext.HttpContext.Session[LocaleSessionKey] = locale;
            }

            // Configure the localisation provider - this is used by lower levels (such as the model) to obtain
            // the locale information
            var localisationProvider = ServiceLocator.Current.GetInstance<ILocalisationProvider>();
            localisationProvider.SetUserLocaleSettings(locale);

            _localeSettings = locale;
        }

        /// <summary>
        /// Allows locale settings to be reset
        /// </summary>
        protected virtual void ClearLocaleSettings()
        {
            ControllerContext.HttpContext.Session.Remove(LocaleSessionKey);
            _localeSettings = null;
        }

        /// <summary>
        /// A root exception handler that catches unhandled controller exceptions, logs them as errors, and redirects
        /// to an error page.
        /// </summary>
        protected override void OnException(ExceptionContext filterContext)
        {
            base.OnException(filterContext);
            Logger.Error("Unhandled exception", filterContext.Exception);
#if !DEBUG
            filterContext.ExceptionHandled = true;
            filterContext.Result = RedirectToAction("Error", "Home");
#endif
        }
    }
}
